package com.apiinvoke.config;

import com.apiinvoke.CommonData;
import com.apiinvoke.annontion.ApiService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Component
public class ApiCache implements CommandLineRunner {

    private final String BASE_PACKAGE = "com.apiinvoke";
    private final String RESOURCE_PATTERN = "/service/**/*.class";
    Map<String, Method> handlerMap = new HashMap<>();

    @Override
    public void run(String... args) {
        //spring工具类，可以获取指定路径下的全部类
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        try {
            String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + RESOURCE_PATTERN;
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            //MetadataReader 的工厂类
            MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                //用于读取类信息
                MetadataReader reader = readerfactory.getMetadataReader(resource);
                //扫描到的class
                String classname = reader.getClassMetadata().getClassName();
                Class<?> clazz = Class.forName(classname);
                if (clazz.isInterface()) {
                    continue;
                }
                final Method[] methods = clazz.getMethods();
                if (methods.length > 0) {
                    for (Method method : methods) {
                        ApiService anno = method.getAnnotation(ApiService.class);
                        if (anno != null) {
                            final Type[] genericParameterTypes = method.getGenericParameterTypes();
                            if (genericParameterTypes.length != 1 || Arrays.stream(genericParameterTypes).noneMatch(v -> v == CommonData.class)) {
                                throw new RuntimeException("必须CommonData为参数");
                            }
                            String key = anno.name();
                            if (!StringUtils.hasText(anno.name())) {
                                key = method.getName();
                            }
                            //将注解中的类型值作为key，对应的类作为 value
                            if (handlerMap.containsKey(key)) {
                                throw new RuntimeException(key + "，重复，package：" + classname + "," + handlerMap.get(key));
                            }
                            handlerMap.put(key, method);
                        }
                    }
                }
            }
            final Iterator<Map.Entry<String, Method>> iterator = handlerMap.entrySet().iterator();
            while (iterator.hasNext()) {
                final Map.Entry<String, Method> next = iterator.next();
                System.out.println(next.getKey() + ":" + next.getValue());
            }

        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public Method getMethod(String apiname) {
        return handlerMap.get(apiname);
    }
}
